package com.gbase8c.dmt.db.oracle;

import com.gbase8c.dmt.db.object.FunctionObject;
import com.gbase8c.dmt.model.migration.config.Type;
import com.gbase8c.dmt.model.migration.dto.DataSourceDto;
import com.gbase8c.dmt.model.migration.dto.FunctionDto;
import lombok.extern.slf4j.Slf4j;
import org.antlr.generated.Processor;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.dbutils.handlers.ColumnListHandler;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Map;

@Slf4j
public class FunctionObjectImpl extends MetaImpl implements FunctionObject {

    public FunctionObjectImpl(DataSourceDto dataSourceDto) {
        super(dataSourceDto);
    }

    @Override
    public List<String> getNames(Map<String, Object> params) {
        String schema = (String) params.get("schema");
        String sql = "select object_name from all_objects where owner = ? and object_type = 'FUNCTION' and STATUS = 'VALID'";
        List<String> functionNames = query(sql, new ColumnListHandler<String>(), schema);
        return functionNames;
    }

    @Override
    public FunctionDto get(String name, Map<String, Object> params) {
        FunctionDto dto = null;
        String schema = (String) params.get("schema");
        String sql = "select text from all_source where owner = ? and type = 'FUNCTION' and name = ? order by line asc";
        List<String> functionTexts = query(sql, new ColumnListHandler<String>(), schema, name);
        if (functionTexts != null && !functionTexts.isEmpty()) {
            String functionStr = StringUtils.join(functionTexts, "\n");
            try {
                dto = Processor.getFunctionDto(functionStr);
                dto.setSchema(schema);
                //  init parameter and variable dataType
                //  init sqlType
                initType(dto);
                if (CollectionUtils.isNotEmpty(dto.getParamDtos())) {
                    for (FunctionDto.Parameter parameter : dto.getParamDtos()) {
                        initType(parameter);
                    }
                }
                if (CollectionUtils.isNotEmpty(dto.getVarDtos())) {
                    for (FunctionDto.Variable variable : dto.getVarDtos()) {
                        initType(variable);
                    }
                }
            } catch (Exception e) {
                log.error(String.format("parse function text[%s] error!", functionStr), e);
                dto = FunctionDto.builder()
                        .schema(schema)
                        .name(name)
                        .srcFuncText(functionStr)
                        .initializable(false)
                        .msg("function解析失败")
                        .build();
            }
        }
        return dto;
    }

    @Override
    public FunctionDto convert(FunctionDto functionDto, Map<String, Object> params) {
        return null;
    }

    @Override
    public String sql(FunctionDto functionDto, Map<String, Object> params) {
        return null;
    }

    private void initType(Type type) {
        String srcType = type.getSrcType();
        srcType = srcType.toUpperCase();
        if (srcType.contains("(")) {
            String dt = srcType.substring(0, srcType.indexOf("("));
            type.setDataType(dt);
            type.setSqlType(toSqlType(dt));
            String psStr = srcType.substring(srcType.indexOf("(") + 1, srcType.length() - 1);
            if (psStr.contains(",")) {
                String[] ps = psStr.replaceAll(" ", "").split(",");
                type.setDataPrecision(Integer.valueOf(ps[0]));
                type.setDataScale(Integer.valueOf(ps[1]));
            } else {
                type.setDataType(srcType);
                type.setSqlType(toSqlType(srcType));
                type.setDataLength(Integer.valueOf(psStr));
            }
        } else {
            type.setDataType(srcType);
            type.setSqlType(toSqlType(srcType));
        }
        if (srcType.contains("NUMBER")) {
            type.setDataLength(22);
        }
    }

}